Objective of workshop

To work with vectors, a key data type in R, and learn to use built-in functions on those vectors.

What will this workshop cover?

In this workshop, the aim is to cover some basics of using variables and vectors in R. We will be covering:

  • Vectors
  • Introduction to functions
  • Use indexing to extract information from a vector

Vectors

A vector is a set of information contained together in a specific order.

To make a vector you combine variables using the c() function (more on functions later); also known as concatenation. To call the c() function we use brackets () with the numbers we want separated by a comma.

The first way of making a vector is to add the arguments you want, numbers in this case.

Run this code chunk to test it out.

vect1 <- c(1,6,19,4,9)
vect1
## [1]  1  6 19  4  9

We can also combine predefined variables and vectors to create a new vector.

x <- 30
vect2 <- c(vect1, 22, 7, x)
vect2
## [1]  1  6 19  4  9 22  7 30

Another way of making a vector is using the colon (:), which can be done without the c function. We can tell R to select a sequence of integers from x to y, or 5 through to 10 in our example.

vect3 <- 5:10
vect3
## [1]  5  6  7  8  9 10

We can also do some basic calculations on vectors. These occur elementwise (one element at a time).

vect3/5
## [1] 1.0 1.2 1.4 1.6 1.8 2.0

As you can see this divides all elements in the vector by 5.

Vector exercise 1

  1. Make a vector called x with integers from 8 through to 14
  2. Add (plus) 5 to your x vector (be sure to save as result back to x)
  3. Make a vector called y with variables 34, 55, 13, 71, 98, 43 and 25
  4. Take (subtract) 12 from your y vector (be sure to save as result back to y)
  5. Times x vector by y
# your code here

Functions: what are they and how to use them

A function is code organised together to perform a specific task. The function will take in an input, perform a task, then return an output. They are the backbone of R, which comes built in with a wide array of functions.

The function(input) format is the fundamental way to call and use a function in R. function is the name of the function we are using, input is the argument or data we are passing to the function.

For example:

# running times (mins)
run_times <- c(31, 50, 15, 19, 23, 34, 9)
# mean running time
aveRun <- mean(run_times)
aveRun
## [1] 25.85714
# tidy up result
aveRun <- round(aveRun, digits = 2)
aveRun
## [1] 25.86

Here we are using the functions c() to concatenate, mean() calculates the mean, and round() rounds to specific decimal places. Notice with the round() function we have digits = 2, which tells the function to round to two decimal places; this is called a argument.

Functions exercise

We are on a walking exercise plan, where we increase our step count by a five hundred each day, starting at 1000 steps and ending on 12000.

  1. Make a variable called steps using the seq() function that increases steps from 1000 to 12000 by increments of 500
  2. Calculate the sum of your steps, which is the total steps taken in your exercise plan
  3. Workout out the median amount of steps we have done on this exercise plan
  4. Comment your code
# your code here

Plotting vectors

As well as functions to find averages, we can also use plotting functions. This is helpful to take a quick look at our data, which is often easier to read then just looking at the numbers themselves. Base R provides two useful functions called hist() and plot().

hist() makes histograms of vectors. Here we can look at running times over a two week period.

run_times <- c(30.08, 28.63, 28.91, 28.24, 33.10, 29.69, 37.81,
               27.00, 31.71, 29.59, 26.25, 28.85, 32.04, 31.44)
hist(run_times)

plot() by default makes scatter plots. Here we make a vector called days and plot it with our running times. We have also added a title using the main = parameter.

days <- 1:14

plot(x = days, y = run_times,
     main = "Running time for each day of week")

To make a different visualisation we can use the type parameter. Here we make our scatter plot a line plot instead, which makes a bit more sense.

plot(x = days, y = run_times,
     main = "Running time for each day of week",
     type = "l")

Later in the R workshops, R Data Visualisation 1 & 2, we go more into plotting and will be using the popular ggplot2 library. For now though, the base plotting functions are very handy tools.

Plotting vectors exercise

You have been asked to review the exam and coursework grades for a module. The lecturer wants to check if the exam or coursework were too easy or hard. If too easy, they would expect more scores greater then 70, if too hard they would expect more scores around 50 or less.

Each student represents a position in each vector. For example, student 1 has a coursework grade of 58, and an exam grade of 80.

Using the hist() and plot() functions:

  1. Make a histogram of coursework_grades. What do you make of the distribution of grades?
  2. Make a histogram of exam_grades. What do you make of the distribution of grades?
  3. Make a scatter plot of coursework_grades and exam_grades. Add a title such as “Exam vs coursework grades on module x”. Is there any pattern at all between coursework grades and exam grades?
coursework_grades <- c(58, 68, 75, 75, 62, 62, 68, 55, 58, 62, 75, 58, 72, 65, 65, 41, 81, 69)
exam_grades <- c(80, 68, 63, 54, 42, 51, 41, 67, 53, 72, 69, 53, 70, 68, 51, 55, 72, 68)

# your code here

Indexing vectors

Indexing is a technical term for accessing elements of a vector. Think of it like selecting books from a book shelf. The vector is your book shelf, the index determines the book, or books you pick from the shelf.

Designed by macrovector / Freepik
Designed by macrovector / Freepik

To index in R you use the square brackets [] after you type the name of the vector to index from. You then put the numerical position of the elements you want to index in the square brackets. For example, if I wanted to select the first element from my vector I would do something like data[1]; data is my data, and 1 is the element I want to index.

Run the example code chunks to see the results:

someNumbers <- c(4, 26, 11, 15, 18, 9, 3, 1)
# indexing the 6th element
someNumbers[6]
## [1] 9

Indexing elements 1 to 4

someNumbers[1:4]
## [1]  4 26 11 15

Dropping elements 5 to 7

someNumbers[-5:-7]
## [1]  4 26 11 15  1

Indexing 1, 5, and 8

someNumbers[c(1,5,8)]
## [1]  4 18  1

Indexing exercise 1

You’ve been keeping track of how much coffee you drink each day for a two week period. We want to split this into week 1 and 2. Using the code below follow the following steps:

  1. Find out the mean for week_one and week_two vectors.
  2. mean doesn’t work for week_two and gives back NA. Print your week_two vector to look at the data.
  3. Check the length of your week_two vector by running the length() function on the week_two vector.
  4. There are a few ways ways to fix this, try and find at least two different ways.

hint: the mean() function has an argument called na.rm, type and run ?mean() to look at the help page

# vector with n coffee per day for two weeks
coffee <- c(3, 5, 4, 2, 3, 1, 1, 6, 2, 3, 2, 4, 2, 1)

# weeks
week_one <- coffee[1:7]
week_two <- coffee[8:15]

# your code here

Using indexing to change values

Using indexing you can change the value of an item, or multiple items, in a vector. This is very useful if you spot a data error and want to fix it in the code. We will using similar principles in later sessions.

This is a combination of what we have learned so far, with reassigning data to variables/vectors and indexing. For example, data[1] <- 5 means we take the first element (or data point) from data, and assign the number 5 as a replacement.

Run the code below to see the example:

someNumbers <- c(4, 26, 11, 15, 18, 9, 3, 1)
someNumbers
## [1]  4 26 11 15 18  9  3  1
# Change one item
someNumbers[8] <- 50
someNumbers
## [1]  4 26 11 15 18  9  3 50
# Change multiple
someNumbers[1:3] <- c(19, 20, 21)
someNumbers
## [1] 19 20 21 15 18  9  3 50

In the first change, we changed the 8th element of the someNumbers data to 50 (it was 1 previously). In the second change, we changed the first, second and third elements to 19, 20, and 21 (changing from 4, 26, 11).

Indexing exercise 2

You wanted to calculate bmi health metrics for your family members, and have collected their weights and heights below. We want all heights to be in meters, and all weights to be in kilograms. Robin has used centimetres for height, Sam (Mum) has used feet for height, Sam (Mum) and Jules (Dad) have used stone for weight.

  1. Convert Sam (Mum)’s height from feet to meters. The calculation is feet multiplied by 0.0328084.

  2. Convert Robin’s height from centimetres to meters. The calculation is centimetres divided by 100.

  3. Convert Sam (Mum) and Jules (Dad)’s weights from stone to kilograms. The calculation is stone multiplied by 6.35029318.

  4. Calculate the bmi for all family names and store in a vector called family_bmi.

  5. Calcuate the average bmi of the family members and store in a variable called avg_bmi.

  6. Add the family names to the family_bmi vector. Searching online for creating named vectors should help.

  7. Print both the family_bmi and avg_bmi calculations.

family_names <- c("Andrew", "Sam (Mum)", "Jules (Dad)", "Ash", "Robin")
family_heights <- c(1.95, 5.09, 1.65, 1.91, 186)
family_weights <- c(94, 9.135, 9.6075, 89, 81)

# your code here

Final task - Please give us your individual feedback!

We would be grateful if you could take a minute before the end of the workshop so we can get your feedback!

https://lse.eu.qualtrics.com/jfe/form/SV_6eSrOVWuit28qcS?coursename=R%Fundamentals%2:%Vectors,%Functions,%and%Indexing&topic=R&prog=DS&version=23-24&link=https://lsecloud.sharepoint.com/:f:/s/TEAM_APD-DSL-Digital-Skills-Trainers/EmUo-IOFzsxFjPujn5poqp4BKnYT46Eg1qoA5o1fSHr6Lw?e=UGNzwj

The solutions will be available from a link at the end of the survey.

Individual coding challenge 1

You decide to calculate your commuting times over a weekly period. You decide to see if you can workout, based off your weekly commute, how much commuting you will do on average this month.

  1. Replicate the commute variable four times using rep() and assign to a variable called commute_est.
  2. Calculate the mean of commute_est and assign to a variable called aveCommute.
  3. Round the value of aveCommute to two decimal places using round() and assign to aveCommute.
  4. You miss timed your Tuesday commute, it should be 37 instead of 33. To make replacement easier use sort() on commute_est, and assign to a variable called commute_sort.
  5. Replace the 33 values with 37 using indexing in the variable commute_sort.
  6. Re-calculate and round aveCommute as per instructions two and three.
  7. Test out the following functions on the commute_sort variable: unique() and sort(commute, decreasing = TRUE).
commute <- c(41, 33, 44, 52, 36, 39)
# enter your code here

Individual coding challenge 2

For this individual coding challenge we will be looking at Lional Messi’s season appearances and goals from 2004-2020.

The code below has been jumbled up and will not run. Your challenge is to re-order it so it runs correctly. It should print out summary statistics for season goal ratio and age band goal ratios, as well as which year was his most and least prolific, and how many years that took him.

# print career ratio
careerGoalRatio
## Error in eval(expr, envir, enclos): object 'careerGoalRatio' not found
# which season had the worst goal ratio
season[which.max(goalRatio)]
## Error in eval(expr, envir, enclos): object 'season' not found
# combine age band ratios to a vector
ageGoalRatio <- c(round(mean(teenageGoalRatio), digits = 2), 
              round(mean(twentiesGoalRatio), digits = 2),
              round(mean(thirtiesGoalRatio), digits = 2))
## Error in eval(expr, envir, enclos): object 'teenageGoalRatio' not found
# add in appearance, goal and season data
appearances <- c(9,25,36,40,51,53,55,60,50,46,57,49,52,54,50,44)
goals <- c(1,8,17,16,38,47,53,73,60,41,58,41,54,45,51,31)
season <- c(2004,2005,2006,2007,2008,2009,2010,2011,2012,
            2013,2014,2015,2016,2017,2018,2019)

# which season had the best goal ratio
season[which.min(goalRatio)]
## Error in eval(expr, envir, enclos): object 'goalRatio' not found
# goal ratio per age band (teenager, 20's, 30's)
teenageGoalRatio <- goalRatio[1:3]
## Error in eval(expr, envir, enclos): object 'goalRatio' not found
twentiesGoalRatio <- goalRatio[4:13]
## Error in eval(expr, envir, enclos): object 'goalRatio' not found
thirtiesGoalRatio <- goalRatio[14:16]
## Error in eval(expr, envir, enclos): object 'goalRatio' not found
# summary results
summary(goalRatio)
## Error in eval(expr, envir, enclos): object 'goalRatio' not found
summary(ageGoalRatio)
## Error in eval(expr, envir, enclos): object 'ageGoalRatio' not found
# how many years playing to reach best goal ratio
season[which.min(goalRatio)] - season[1]
## Error in eval(expr, envir, enclos): object 'goalRatio' not found
# work out appearance to goal ratio per season and total career ratio
goalRatio <- round(appearances/goals, digits = 2)
careerGoalRatio <- round(sum(appearances)/sum(goals), digits = 2)
LS0tCnRpdGxlOiAiUiBGdW5kYW1lbnRhbHMgMjogVmVjdG9ycywgRnVuY3Rpb25zLCBhbmQgSW5kZXhpbmciCmF1dGhvcjoKICAgLSBuYW1lOiBBbmRyZXcgTW9sZXMKICAgICBhZmZpbGlhdGlvbjogTGVhcm5pbmcgRGV2ZWxvcGVyLCBEaWdpdGFsIFNraWxscyBMYWIKZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJUIsICVZJylgIgpvdXRwdXQ6IAogIGh0bWxfZG9jdW1lbnQ6IAogICAgdGhlbWU6IHJlYWRhYmxlCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzCiAgICBrZWVwX21kOiB5ZXMKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiAKICAgICAgY29sbGFwc2VkOiBmYWxzZQotLS0KCiMgT2JqZWN0aXZlIG9mIHdvcmtzaG9wCgpUbyB3b3JrIHdpdGggdmVjdG9ycywgYSBrZXkgZGF0YSB0eXBlIGluIFIsIGFuZCBsZWFybiB0byB1c2UgYnVpbHQtaW4gZnVuY3Rpb25zIG9uIHRob3NlIHZlY3RvcnMuIAoKIyBXaGF0IHdpbGwgdGhpcyB3b3Jrc2hvcCBjb3Zlcj8KCkluIHRoaXMgd29ya3Nob3AsIHRoZSBhaW0gaXMgdG8gY292ZXIgc29tZSBiYXNpY3Mgb2YgdXNpbmcgdmFyaWFibGVzIGFuZCB2ZWN0b3JzIGluIFIuIFdlIHdpbGwgYmUgY292ZXJpbmc6CgotICAgVmVjdG9ycwotICAgSW50cm9kdWN0aW9uIHRvIGZ1bmN0aW9ucwotICAgVXNlIGluZGV4aW5nIHRvIGV4dHJhY3QgaW5mb3JtYXRpb24gZnJvbSBhIHZlY3RvciAKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyBWZWN0b3JzCgpBIHZlY3RvciBpcyBhIHNldCBvZiBpbmZvcm1hdGlvbiBjb250YWluZWQgdG9nZXRoZXIgaW4gYSBzcGVjaWZpYyBvcmRlci4KClRvIG1ha2UgYSB2ZWN0b3IgeW91IGNvbWJpbmUgdmFyaWFibGVzIHVzaW5nIHRoZSBgYygpYCBmdW5jdGlvbiAobW9yZSBvbiBmdW5jdGlvbnMgbGF0ZXIpOyBhbHNvIGtub3duIGFzIGNvbmNhdGVuYXRpb24uIFRvIGNhbGwgdGhlIGBjKClgIGZ1bmN0aW9uIHdlIHVzZSBicmFja2V0cyAoKSB3aXRoIHRoZSBudW1iZXJzIHdlIHdhbnQgc2VwYXJhdGVkIGJ5IGEgY29tbWEuCgpUaGUgZmlyc3Qgd2F5IG9mIG1ha2luZyBhIHZlY3RvciBpcyB0byBhZGQgdGhlIGFyZ3VtZW50cyB5b3Ugd2FudCwgbnVtYmVycyBpbiB0aGlzIGNhc2UuCgpSdW4gdGhpcyBjb2RlIGNodW5rIHRvIHRlc3QgaXQgb3V0LgoKYGBge3J9CnZlY3QxIDwtIGMoMSw2LDE5LDQsOSkKdmVjdDEKYGBgCgpXZSBjYW4gYWxzbyBjb21iaW5lIHByZWRlZmluZWQgdmFyaWFibGVzIGFuZCB2ZWN0b3JzIHRvIGNyZWF0ZSBhIG5ldyB2ZWN0b3IuCgpgYGB7cn0KeCA8LSAzMAp2ZWN0MiA8LSBjKHZlY3QxLCAyMiwgNywgeCkKdmVjdDIKYGBgCgpBbm90aGVyIHdheSBvZiBtYWtpbmcgYSB2ZWN0b3IgaXMgdXNpbmcgdGhlIGNvbG9uIChgOmApLCB3aGljaCBjYW4gYmUgZG9uZSB3aXRob3V0IHRoZSBjIGZ1bmN0aW9uLiBXZSBjYW4gdGVsbCBSIHRvIHNlbGVjdCBhIHNlcXVlbmNlIG9mIGludGVnZXJzIGZyb20geCB0byB5LCBvciA1IHRocm91Z2ggdG8gMTAgaW4gb3VyIGV4YW1wbGUuCgpgYGB7cn0KdmVjdDMgPC0gNToxMAp2ZWN0MwpgYGAKCldlIGNhbiBhbHNvIGRvIHNvbWUgYmFzaWMgY2FsY3VsYXRpb25zIG9uIHZlY3RvcnMuIFRoZXNlIG9jY3VyIGVsZW1lbnR3aXNlIChvbmUgZWxlbWVudCBhdCBhIHRpbWUpLgoKYGBge3J9CnZlY3QzLzUKYGBgCgpBcyB5b3UgY2FuIHNlZSB0aGlzIGRpdmlkZXMgYWxsIGVsZW1lbnRzIGluIHRoZSB2ZWN0b3IgYnkgNS4KCiMjIFZlY3RvciBleGVyY2lzZSAxCgoxKSAgTWFrZSBhIHZlY3RvciBjYWxsZWQgeCB3aXRoIGludGVnZXJzIGZyb20gOCB0aHJvdWdoIHRvIDE0CjIpICBBZGQgKHBsdXMpIDUgdG8geW91ciB4IHZlY3RvciAoYmUgc3VyZSB0byBzYXZlIGFzIHJlc3VsdCBiYWNrIHRvIHgpCjMpICBNYWtlIGEgdmVjdG9yIGNhbGxlZCB5IHdpdGggdmFyaWFibGVzIDM0LCA1NSwgMTMsIDcxLCA5OCwgNDMgYW5kIDI1CjQpICBUYWtlIChzdWJ0cmFjdCkgMTIgZnJvbSB5b3VyIHkgdmVjdG9yIChiZSBzdXJlIHRvIHNhdmUgYXMgcmVzdWx0IGJhY2sgdG8geSkKNSkgIFRpbWVzIHggdmVjdG9yIGJ5IHkKCmBgYHtyfQojIHlvdXIgY29kZSBoZXJlCgoKYGBgCgojIEZ1bmN0aW9uczogd2hhdCBhcmUgdGhleSBhbmQgaG93IHRvIHVzZSB0aGVtCgpBIGZ1bmN0aW9uIGlzIGNvZGUgb3JnYW5pc2VkIHRvZ2V0aGVyIHRvIHBlcmZvcm0gYSBzcGVjaWZpYyB0YXNrLiBUaGUgZnVuY3Rpb24gd2lsbCB0YWtlIGluIGFuIGlucHV0LCBwZXJmb3JtIGEgdGFzaywgdGhlbiByZXR1cm4gYW4gb3V0cHV0LiBUaGV5IGFyZSB0aGUgYmFja2JvbmUgb2YgUiwgd2hpY2ggY29tZXMgYnVpbHQgaW4gd2l0aCBhIHdpZGUgYXJyYXkgb2YgZnVuY3Rpb25zLgoKVGhlICoqZnVuY3Rpb24oaW5wdXQpKiogZm9ybWF0IGlzIHRoZSBmdW5kYW1lbnRhbCB3YXkgdG8gY2FsbCBhbmQgdXNlIGEgZnVuY3Rpb24gaW4gUi4gKipmdW5jdGlvbioqIGlzIHRoZSBuYW1lIG9mIHRoZSBmdW5jdGlvbiB3ZSBhcmUgdXNpbmcsICoqaW5wdXQqKiBpcyB0aGUgYXJndW1lbnQgb3IgZGF0YSB3ZSBhcmUgcGFzc2luZyB0byB0aGUgZnVuY3Rpb24uCgpGb3IgZXhhbXBsZToKCmBgYHtyfQojIHJ1bm5pbmcgdGltZXMgKG1pbnMpCnJ1bl90aW1lcyA8LSBjKDMxLCA1MCwgMTUsIDE5LCAyMywgMzQsIDkpCiMgbWVhbiBydW5uaW5nIHRpbWUKYXZlUnVuIDwtIG1lYW4ocnVuX3RpbWVzKQphdmVSdW4KIyB0aWR5IHVwIHJlc3VsdAphdmVSdW4gPC0gcm91bmQoYXZlUnVuLCBkaWdpdHMgPSAyKQphdmVSdW4KYGBgCgpIZXJlIHdlIGFyZSB1c2luZyB0aGUgZnVuY3Rpb25zIGBjKClgIHRvIGNvbmNhdGVuYXRlLCBgbWVhbigpYCBjYWxjdWxhdGVzIHRoZSBtZWFuLCBhbmQgYHJvdW5kKClgIHJvdW5kcyB0byBzcGVjaWZpYyBkZWNpbWFsIHBsYWNlcy4gTm90aWNlIHdpdGggdGhlIGByb3VuZCgpYCBmdW5jdGlvbiB3ZSBoYXZlIGBkaWdpdHMgPSAyYCwgd2hpY2ggdGVsbHMgdGhlIGZ1bmN0aW9uIHRvIHJvdW5kIHRvIHR3byBkZWNpbWFsIHBsYWNlczsgdGhpcyBpcyBjYWxsZWQgYSAqYXJndW1lbnQqLgoKIyMgRnVuY3Rpb25zIGV4ZXJjaXNlCgpXZSBhcmUgb24gYSB3YWxraW5nIGV4ZXJjaXNlIHBsYW4sIHdoZXJlIHdlIGluY3JlYXNlIG91ciBzdGVwIGNvdW50IGJ5IGEgZml2ZSBodW5kcmVkIGVhY2ggZGF5LCBzdGFydGluZyBhdCAxMDAwIHN0ZXBzIGFuZCBlbmRpbmcgb24gMTIwMDAuCgoxKSAgTWFrZSBhIHZhcmlhYmxlIGNhbGxlZCBzdGVwcyB1c2luZyB0aGUgYHNlcSgpYCBmdW5jdGlvbiB0aGF0IGluY3JlYXNlcyBzdGVwcyBmcm9tIDEwMDAgdG8gMTIwMDAgYnkgaW5jcmVtZW50cyBvZiA1MDAKMikgIENhbGN1bGF0ZSB0aGUgc3VtIG9mIHlvdXIgc3RlcHMsIHdoaWNoIGlzIHRoZSB0b3RhbCBzdGVwcyB0YWtlbiBpbiB5b3VyIGV4ZXJjaXNlIHBsYW4KMykgIFdvcmtvdXQgb3V0IHRoZSBtZWRpYW4gYW1vdW50IG9mIHN0ZXBzIHdlIGhhdmUgZG9uZSBvbiB0aGlzIGV4ZXJjaXNlIHBsYW4KNCkgIENvbW1lbnQgeW91ciBjb2RlCgpgYGB7cn0KIyB5b3VyIGNvZGUgaGVyZQoKCmBgYAoKIyBQbG90dGluZyB2ZWN0b3JzCgpBcyB3ZWxsIGFzIGZ1bmN0aW9ucyB0byBmaW5kIGF2ZXJhZ2VzLCB3ZSBjYW4gYWxzbyB1c2UgcGxvdHRpbmcgZnVuY3Rpb25zLiBUaGlzIGlzIGhlbHBmdWwgdG8gdGFrZSBhIHF1aWNrIGxvb2sgYXQgb3VyIGRhdGEsIHdoaWNoIGlzIG9mdGVuIGVhc2llciB0byByZWFkIHRoZW4ganVzdCBsb29raW5nIGF0IHRoZSBudW1iZXJzIHRoZW1zZWx2ZXMuIEJhc2UgUiBwcm92aWRlcyB0d28gdXNlZnVsIGZ1bmN0aW9ucyBjYWxsZWQgYGhpc3QoKWAgYW5kIGBwbG90KClgLiAKCmBoaXN0KClgIG1ha2VzIGhpc3RvZ3JhbXMgb2YgdmVjdG9ycy4gSGVyZSB3ZSBjYW4gbG9vayBhdCBydW5uaW5nIHRpbWVzIG92ZXIgYSB0d28gd2VlayBwZXJpb2QuIApgYGB7cn0KcnVuX3RpbWVzIDwtIGMoMzAuMDgsIDI4LjYzLCAyOC45MSwgMjguMjQsIDMzLjEwLCAyOS42OSwgMzcuODEsCiAgICAgICAgICAgICAgIDI3LjAwLCAzMS43MSwgMjkuNTksIDI2LjI1LCAyOC44NSwgMzIuMDQsIDMxLjQ0KQpoaXN0KHJ1bl90aW1lcykKYGBgCgpgcGxvdCgpYCBieSBkZWZhdWx0IG1ha2VzIHNjYXR0ZXIgcGxvdHMuIEhlcmUgd2UgbWFrZSBhIHZlY3RvciBjYWxsZWQgZGF5cyBhbmQgcGxvdCBpdCB3aXRoIG91ciBydW5uaW5nIHRpbWVzLiBXZSBoYXZlIGFsc28gYWRkZWQgYSB0aXRsZSB1c2luZyB0aGUgYG1haW4gPWAgcGFyYW1ldGVyLiAKYGBge3J9CmRheXMgPC0gMToxNAoKcGxvdCh4ID0gZGF5cywgeSA9IHJ1bl90aW1lcywKICAgICBtYWluID0gIlJ1bm5pbmcgdGltZSBmb3IgZWFjaCBkYXkgb2Ygd2VlayIpCmBgYAoKVG8gbWFrZSBhIGRpZmZlcmVudCB2aXN1YWxpc2F0aW9uIHdlIGNhbiB1c2UgdGhlIHR5cGUgcGFyYW1ldGVyLiBIZXJlIHdlIG1ha2Ugb3VyIHNjYXR0ZXIgcGxvdCBhIGxpbmUgcGxvdCBpbnN0ZWFkLCB3aGljaCBtYWtlcyBhIGJpdCBtb3JlIHNlbnNlLiAKYGBge3J9CnBsb3QoeCA9IGRheXMsIHkgPSBydW5fdGltZXMsCiAgICAgbWFpbiA9ICJSdW5uaW5nIHRpbWUgZm9yIGVhY2ggZGF5IG9mIHdlZWsiLAogICAgIHR5cGUgPSAibCIpCmBgYAoKTGF0ZXIgaW4gdGhlIFIgd29ya3Nob3BzLCBSIERhdGEgVmlzdWFsaXNhdGlvbiAxICYgMiwgd2UgZ28gbW9yZSBpbnRvIHBsb3R0aW5nIGFuZCB3aWxsIGJlIHVzaW5nIHRoZSBwb3B1bGFyIGdncGxvdDIgbGlicmFyeS4gRm9yIG5vdyB0aG91Z2gsIHRoZSBiYXNlIHBsb3R0aW5nIGZ1bmN0aW9ucyBhcmUgdmVyeSBoYW5keSB0b29scy4gCgojIyBQbG90dGluZyB2ZWN0b3JzIGV4ZXJjaXNlCgpZb3UgaGF2ZSBiZWVuIGFza2VkIHRvIHJldmlldyB0aGUgZXhhbSBhbmQgY291cnNld29yayBncmFkZXMgZm9yIGEgbW9kdWxlLiBUaGUgbGVjdHVyZXIgd2FudHMgdG8gY2hlY2sgaWYgdGhlIGV4YW0gb3IgY291cnNld29yayB3ZXJlIHRvbyBlYXN5IG9yIGhhcmQuIElmIHRvbyBlYXN5LCB0aGV5IHdvdWxkIGV4cGVjdCBtb3JlIHNjb3JlcyBncmVhdGVyIHRoZW4gNzAsIGlmIHRvbyBoYXJkIHRoZXkgd291bGQgZXhwZWN0IG1vcmUgc2NvcmVzIGFyb3VuZCA1MCBvciBsZXNzLiAKCkVhY2ggc3R1ZGVudCByZXByZXNlbnRzIGEgcG9zaXRpb24gaW4gZWFjaCB2ZWN0b3IuIEZvciBleGFtcGxlLCBzdHVkZW50IDEgaGFzIGEgY291cnNld29yayBncmFkZSBvZiA1OCwgYW5kIGFuIGV4YW0gZ3JhZGUgb2YgODAuIAoKVXNpbmcgdGhlIGBoaXN0KClgIGFuZCBgcGxvdCgpYCBmdW5jdGlvbnM6CgoxKSBNYWtlIGEgaGlzdG9ncmFtIG9mIGBjb3Vyc2V3b3JrX2dyYWRlc2AuIFdoYXQgZG8geW91IG1ha2Ugb2YgdGhlIGRpc3RyaWJ1dGlvbiBvZiBncmFkZXM/CjIpIE1ha2UgYSBoaXN0b2dyYW0gb2YgYGV4YW1fZ3JhZGVzYC4gV2hhdCBkbyB5b3UgbWFrZSBvZiB0aGUgZGlzdHJpYnV0aW9uIG9mIGdyYWRlcz8KMykgTWFrZSBhIHNjYXR0ZXIgcGxvdCBvZiBgY291cnNld29ya19ncmFkZXNgIGFuZCBgZXhhbV9ncmFkZXNgLiBBZGQgYSB0aXRsZSBzdWNoIGFzICJFeGFtIHZzIGNvdXJzZXdvcmsgZ3JhZGVzIG9uIG1vZHVsZSB4Ii4gSXMgdGhlcmUgYW55IHBhdHRlcm4gYXQgYWxsIGJldHdlZW4gY291cnNld29yayBncmFkZXMgYW5kIGV4YW0gZ3JhZGVzPwoKYGBge3J9CmNvdXJzZXdvcmtfZ3JhZGVzIDwtIGMoNTgsIDY4LCA3NSwgNzUsIDYyLCA2MiwgNjgsIDU1LCA1OCwgNjIsIDc1LCA1OCwgNzIsIDY1LCA2NSwgNDEsIDgxLCA2OSkKZXhhbV9ncmFkZXMgPC0gYyg4MCwgNjgsIDYzLCA1NCwgNDIsIDUxLCA0MSwgNjcsIDUzLCA3MiwgNjksIDUzLCA3MCwgNjgsIDUxLCA1NSwgNzIsIDY4KQoKIyB5b3VyIGNvZGUgaGVyZQoKCmBgYAoKCiMgSW5kZXhpbmcgdmVjdG9ycwoKSW5kZXhpbmcgaXMgYSB0ZWNobmljYWwgdGVybSBmb3IgYWNjZXNzaW5nIGVsZW1lbnRzIG9mIGEgdmVjdG9yLiBUaGluayBvZiBpdCBsaWtlIHNlbGVjdGluZyBib29rcyBmcm9tIGEgYm9vayBzaGVsZi4gVGhlIHZlY3RvciBpcyB5b3VyIGJvb2sgc2hlbGYsIHRoZSBpbmRleCBkZXRlcm1pbmVzIHRoZSBib29rLCBvciBib29rcyB5b3UgcGljayBmcm9tIHRoZSBzaGVsZi4KCiFbRGVzaWduZWQgYnkgbWFjcm92ZWN0b3IgLyBGcmVlcGlrXShodHRwczovL2dpdGh1Yi5jb20vYW5kcmV3bW9sZXMyL3JUcmFpbkludHJvZHVjdGlvbi9ibG9iL21haW4vci1mdW5kYW1lbnRhbHMtMi9pbWFnZXMvNjcxNC5qcGc/cmF3PXRydWUpe3dpZHRoPSIzMCUifQoKVG8gaW5kZXggaW4gUiB5b3UgdXNlIHRoZSBzcXVhcmUgYnJhY2tldHMgYFtdYCBhZnRlciB5b3UgdHlwZSB0aGUgbmFtZSBvZiB0aGUgdmVjdG9yIHRvIGluZGV4IGZyb20uIFlvdSB0aGVuIHB1dCB0aGUgbnVtZXJpY2FsIHBvc2l0aW9uIG9mIHRoZSBlbGVtZW50cyB5b3Ugd2FudCB0byBpbmRleCBpbiB0aGUgc3F1YXJlIGJyYWNrZXRzLiBGb3IgZXhhbXBsZSwgaWYgSSB3YW50ZWQgdG8gc2VsZWN0IHRoZSBmaXJzdCBlbGVtZW50IGZyb20gbXkgdmVjdG9yIEkgd291bGQgZG8gc29tZXRoaW5nIGxpa2UgYGRhdGFbMV1gOyBkYXRhIGlzIG15IGRhdGEsIGFuZCAxIGlzIHRoZSBlbGVtZW50IEkgd2FudCB0byBpbmRleC4KClJ1biB0aGUgZXhhbXBsZSBjb2RlIGNodW5rcyB0byBzZWUgdGhlIHJlc3VsdHM6CgpgYGB7cn0Kc29tZU51bWJlcnMgPC0gYyg0LCAyNiwgMTEsIDE1LCAxOCwgOSwgMywgMSkKIyBpbmRleGluZyB0aGUgNnRoIGVsZW1lbnQKc29tZU51bWJlcnNbNl0KYGBgCgpJbmRleGluZyBlbGVtZW50cyAxIHRvIDQKCmBgYHtyfQpzb21lTnVtYmVyc1sxOjRdCmBgYAoKRHJvcHBpbmcgZWxlbWVudHMgNSB0byA3CgpgYGB7cn0Kc29tZU51bWJlcnNbLTU6LTddCmBgYAoKSW5kZXhpbmcgMSwgNSwgYW5kIDgKCmBgYHtyfQpzb21lTnVtYmVyc1tjKDEsNSw4KV0KYGBgCgojIyBJbmRleGluZyBleGVyY2lzZSAxCgpZb3UndmUgYmVlbiBrZWVwaW5nIHRyYWNrIG9mIGhvdyBtdWNoIGNvZmZlZSB5b3UgZHJpbmsgZWFjaCBkYXkgZm9yIGEgdHdvIHdlZWsgcGVyaW9kLiBXZSB3YW50IHRvIHNwbGl0IHRoaXMgaW50byB3ZWVrIDEgYW5kIDIuIFVzaW5nIHRoZSBjb2RlIGJlbG93IGZvbGxvdyB0aGUgZm9sbG93aW5nIHN0ZXBzOgoKMSkgIEZpbmQgb3V0IHRoZSBtZWFuIGZvciB3ZWVrX29uZSBhbmQgd2Vla190d28gdmVjdG9ycy4KMikgIGBtZWFuYCBkb2Vzbid0IHdvcmsgZm9yIHdlZWtfdHdvIGFuZCBnaXZlcyBiYWNrIGBOQWAuIFByaW50IHlvdXIgd2Vla190d28gdmVjdG9yIHRvIGxvb2sgYXQgdGhlIGRhdGEuCjMpICBDaGVjayB0aGUgbGVuZ3RoIG9mIHlvdXIgd2Vla190d28gdmVjdG9yIGJ5IHJ1bm5pbmcgdGhlIGBsZW5ndGgoKWAgZnVuY3Rpb24gb24gdGhlIHdlZWtfdHdvIHZlY3Rvci4KNCkgIFRoZXJlIGFyZSBhIGZldyB3YXlzIHdheXMgdG8gZml4IHRoaXMsIHRyeSBhbmQgZmluZCBhdCBsZWFzdCB0d28gZGlmZmVyZW50IHdheXMuCgoqaGludDogdGhlIG1lYW4oKSBmdW5jdGlvbiBoYXMgYW4gYXJndW1lbnQgY2FsbGVkIG5hLnJtLCB0eXBlIGFuZCBydW4gP21lYW4oKSB0byBsb29rIGF0IHRoZSBoZWxwIHBhZ2UqCgpgYGB7cn0KIyB2ZWN0b3Igd2l0aCBuIGNvZmZlZSBwZXIgZGF5IGZvciB0d28gd2Vla3MKY29mZmVlIDwtIGMoMywgNSwgNCwgMiwgMywgMSwgMSwgNiwgMiwgMywgMiwgNCwgMiwgMSkKCiMgd2Vla3MKd2Vla19vbmUgPC0gY29mZmVlWzE6N10Kd2Vla190d28gPC0gY29mZmVlWzg6MTVdCgojIHlvdXIgY29kZSBoZXJlCgoKYGBgCgojIFVzaW5nIGluZGV4aW5nIHRvIGNoYW5nZSB2YWx1ZXMKClVzaW5nIGluZGV4aW5nIHlvdSBjYW4gY2hhbmdlIHRoZSB2YWx1ZSBvZiBhbiBpdGVtLCBvciBtdWx0aXBsZSBpdGVtcywgaW4gYSB2ZWN0b3IuIFRoaXMgaXMgdmVyeSB1c2VmdWwgaWYgeW91IHNwb3QgYSBkYXRhIGVycm9yIGFuZCB3YW50IHRvIGZpeCBpdCBpbiB0aGUgY29kZS4gV2Ugd2lsbCB1c2luZyBzaW1pbGFyIHByaW5jaXBsZXMgaW4gbGF0ZXIgc2Vzc2lvbnMuCgpUaGlzIGlzIGEgY29tYmluYXRpb24gb2Ygd2hhdCB3ZSBoYXZlIGxlYXJuZWQgc28gZmFyLCB3aXRoIHJlYXNzaWduaW5nIGRhdGEgdG8gdmFyaWFibGVzL3ZlY3RvcnMgYW5kIGluZGV4aW5nLiBGb3IgZXhhbXBsZSwgYGRhdGFbMV0gPC0gNWAgbWVhbnMgd2UgdGFrZSB0aGUgZmlyc3QgZWxlbWVudCAob3IgZGF0YSBwb2ludCkgZnJvbSBkYXRhLCBhbmQgYXNzaWduIHRoZSBudW1iZXIgNSBhcyBhIHJlcGxhY2VtZW50LgoKUnVuIHRoZSBjb2RlIGJlbG93IHRvIHNlZSB0aGUgZXhhbXBsZToKCmBgYHtyfQpzb21lTnVtYmVycyA8LSBjKDQsIDI2LCAxMSwgMTUsIDE4LCA5LCAzLCAxKQpzb21lTnVtYmVycwojIENoYW5nZSBvbmUgaXRlbQpzb21lTnVtYmVyc1s4XSA8LSA1MApzb21lTnVtYmVycwojIENoYW5nZSBtdWx0aXBsZQpzb21lTnVtYmVyc1sxOjNdIDwtIGMoMTksIDIwLCAyMSkKc29tZU51bWJlcnMKYGBgCgpJbiB0aGUgZmlyc3QgY2hhbmdlLCB3ZSBjaGFuZ2VkIHRoZSA4dGggZWxlbWVudCBvZiB0aGUgc29tZU51bWJlcnMgZGF0YSB0byA1MCAoaXQgd2FzIDEgcHJldmlvdXNseSkuIEluIHRoZSBzZWNvbmQgY2hhbmdlLCB3ZSBjaGFuZ2VkIHRoZSBmaXJzdCwgc2Vjb25kIGFuZCB0aGlyZCBlbGVtZW50cyB0byAxOSwgMjAsIGFuZCAyMSAoY2hhbmdpbmcgZnJvbSA0LCAyNiwgMTEpLgoKIyMgSW5kZXhpbmcgZXhlcmNpc2UgMgoKWW91IHdhbnRlZCB0byBjYWxjdWxhdGUgYm1pIGhlYWx0aCBtZXRyaWNzIGZvciB5b3VyIGZhbWlseSBtZW1iZXJzLCBhbmQgaGF2ZSBjb2xsZWN0ZWQgdGhlaXIgd2VpZ2h0cyBhbmQgaGVpZ2h0cyBiZWxvdy4gV2Ugd2FudCBhbGwgaGVpZ2h0cyB0byBiZSBpbiBtZXRlcnMsIGFuZCBhbGwgd2VpZ2h0cyB0byBiZSBpbiBraWxvZ3JhbXMuIFJvYmluIGhhcyB1c2VkIGNlbnRpbWV0cmVzIGZvciBoZWlnaHQsIFNhbSAoTXVtKSBoYXMgdXNlZCBmZWV0IGZvciBoZWlnaHQsIFNhbSAoTXVtKSBhbmQgSnVsZXMgKERhZCkgaGF2ZSB1c2VkIHN0b25lIGZvciB3ZWlnaHQuCgoxKSBDb252ZXJ0IFNhbSAoTXVtKSdzIGhlaWdodCBmcm9tIGZlZXQgdG8gbWV0ZXJzLiBUaGUgY2FsY3VsYXRpb24gaXMgZmVldCBtdWx0aXBsaWVkIGJ5IDAuMDMyODA4NC4KCjIpIENvbnZlcnQgUm9iaW4ncyBoZWlnaHQgZnJvbSBjZW50aW1ldHJlcyB0byBtZXRlcnMuIFRoZSBjYWxjdWxhdGlvbiBpcyBjZW50aW1ldHJlcyBkaXZpZGVkIGJ5IDEwMC4KCjMpIENvbnZlcnQgU2FtIChNdW0pIGFuZCBKdWxlcyAoRGFkKSdzIHdlaWdodHMgZnJvbSBzdG9uZSB0byBraWxvZ3JhbXMuIFRoZSBjYWxjdWxhdGlvbiBpcyBzdG9uZSBtdWx0aXBsaWVkIGJ5IDYuMzUwMjkzMTguIAoKNCkgQ2FsY3VsYXRlIHRoZSBibWkgZm9yIGFsbCBmYW1pbHkgbmFtZXMgYW5kIHN0b3JlIGluIGEgdmVjdG9yIGNhbGxlZCBmYW1pbHlfYm1pLgoKNSkgQ2FsY3VhdGUgdGhlIGF2ZXJhZ2UgYm1pIG9mIHRoZSBmYW1pbHkgbWVtYmVycyBhbmQgc3RvcmUgaW4gYSB2YXJpYWJsZSBjYWxsZWQgYXZnX2JtaS4KCjYpIEFkZCB0aGUgZmFtaWx5IG5hbWVzIHRvIHRoZSBmYW1pbHlfYm1pIHZlY3Rvci4gU2VhcmNoaW5nIG9ubGluZSBmb3IgY3JlYXRpbmcgbmFtZWQgdmVjdG9ycyBzaG91bGQgaGVscC4gCgo3KSBQcmludCBib3RoIHRoZSBmYW1pbHlfYm1pIGFuZCBhdmdfYm1pIGNhbGN1bGF0aW9ucy4KCgpgYGB7cn0KZmFtaWx5X25hbWVzIDwtIGMoIkFuZHJldyIsICJTYW0gKE11bSkiLCAiSnVsZXMgKERhZCkiLCAiQXNoIiwgIlJvYmluIikKZmFtaWx5X2hlaWdodHMgPC0gYygxLjk1LCA1LjA5LCAxLjY1LCAxLjkxLCAxODYpCmZhbWlseV93ZWlnaHRzIDwtIGMoOTQsIDkuMTM1LCA5LjYwNzUsIDg5LCA4MSkKCiMgeW91ciBjb2RlIGhlcmUKCgpgYGAKCgojIEZpbmFsIHRhc2sgLSBQbGVhc2UgZ2l2ZSB1cyB5b3VyIGluZGl2aWR1YWwgZmVlZGJhY2shCgpXZSB3b3VsZCBiZSBncmF0ZWZ1bCBpZiB5b3UgY291bGQgdGFrZSBhIG1pbnV0ZSBiZWZvcmUgdGhlIGVuZCBvZiB0aGUgd29ya3Nob3Agc28gd2UgY2FuIGdldCB5b3VyIGZlZWRiYWNrIQoKPGh0dHBzOi8vbHNlLmV1LnF1YWx0cmljcy5jb20vamZlL2Zvcm0vU1ZfNmVTck9WV3VpdDI4cWNTP2NvdXJzZW5hbWU9UiVGdW5kYW1lbnRhbHMlMjolVmVjdG9ycywlRnVuY3Rpb25zLCVhbmQlSW5kZXhpbmcmdG9waWM9UiZwcm9nPURTJnZlcnNpb249MjMtMjQmbGluaz1odHRwczovL2xzZWNsb3VkLnNoYXJlcG9pbnQuY29tLzpmOi9zL1RFQU1fQVBELURTTC1EaWdpdGFsLVNraWxscy1UcmFpbmVycy9FbVVvLUlPRnpzeEZqUHVqbjVwb3FwNEJLbllUNDZFZzFxb0E1bzFmU0hyNkx3P2U9VUdOendqPgoKVGhlIHNvbHV0aW9ucyB3aWxsIGJlIGF2YWlsYWJsZSBmcm9tIGEgbGluayBhdCB0aGUgZW5kIG9mIHRoZSBzdXJ2ZXkuCgojIEluZGl2aWR1YWwgY29kaW5nIGNoYWxsZW5nZSAxCgpZb3UgZGVjaWRlIHRvIGNhbGN1bGF0ZSB5b3VyIGNvbW11dGluZyB0aW1lcyBvdmVyIGEgd2Vla2x5IHBlcmlvZC4gWW91IGRlY2lkZSB0byBzZWUgaWYgeW91IGNhbiB3b3Jrb3V0LCBiYXNlZCBvZmYgeW91ciB3ZWVrbHkgY29tbXV0ZSwgaG93IG11Y2ggY29tbXV0aW5nIHlvdSB3aWxsIGRvIG9uIGF2ZXJhZ2UgdGhpcyBtb250aC4KCjEpICBSZXBsaWNhdGUgdGhlIGNvbW11dGUgdmFyaWFibGUgZm91ciB0aW1lcyB1c2luZyBgcmVwKClgIGFuZCBhc3NpZ24gdG8gYSB2YXJpYWJsZSBjYWxsZWQgY29tbXV0ZV9lc3QuCjIpICBDYWxjdWxhdGUgdGhlIG1lYW4gb2YgY29tbXV0ZV9lc3QgYW5kIGFzc2lnbiB0byBhIHZhcmlhYmxlIGNhbGxlZCBhdmVDb21tdXRlLgozKSAgUm91bmQgdGhlIHZhbHVlIG9mIGF2ZUNvbW11dGUgdG8gdHdvIGRlY2ltYWwgcGxhY2VzIHVzaW5nIGByb3VuZCgpYCBhbmQgYXNzaWduIHRvIGF2ZUNvbW11dGUuCjQpICBZb3UgbWlzcyB0aW1lZCB5b3VyIFR1ZXNkYXkgY29tbXV0ZSwgaXQgc2hvdWxkIGJlIDM3IGluc3RlYWQgb2YgMzMuIFRvIG1ha2UgcmVwbGFjZW1lbnQgZWFzaWVyIHVzZSBgc29ydCgpYCBvbiBjb21tdXRlX2VzdCwgYW5kIGFzc2lnbiB0byBhIHZhcmlhYmxlIGNhbGxlZCBjb21tdXRlX3NvcnQuCjUpICBSZXBsYWNlIHRoZSAzMyB2YWx1ZXMgd2l0aCAzNyB1c2luZyBpbmRleGluZyBpbiB0aGUgdmFyaWFibGUgY29tbXV0ZV9zb3J0Lgo2KSAgUmUtY2FsY3VsYXRlIGFuZCByb3VuZCBhdmVDb21tdXRlIGFzIHBlciBpbnN0cnVjdGlvbnMgdHdvIGFuZCB0aHJlZS4KNykgIFRlc3Qgb3V0IHRoZSBmb2xsb3dpbmcgZnVuY3Rpb25zIG9uIHRoZSBjb21tdXRlX3NvcnQgdmFyaWFibGU6IGB1bmlxdWUoKWAgYW5kIGBzb3J0KGNvbW11dGUsIGRlY3JlYXNpbmcgPSBUUlVFKWAuCgpgYGB7cn0KY29tbXV0ZSA8LSBjKDQxLCAzMywgNDQsIDUyLCAzNiwgMzkpCiMgZW50ZXIgeW91ciBjb2RlIGhlcmUKCmBgYAoKIyBJbmRpdmlkdWFsIGNvZGluZyBjaGFsbGVuZ2UgMgoKRm9yIHRoaXMgaW5kaXZpZHVhbCBjb2RpbmcgY2hhbGxlbmdlIHdlIHdpbGwgYmUgbG9va2luZyBhdCBMaW9uYWwgTWVzc2kncyBzZWFzb24gYXBwZWFyYW5jZXMgYW5kIGdvYWxzIGZyb20gMjAwNC0yMDIwLiAKClRoZSBjb2RlIGJlbG93IGhhcyBiZWVuIGp1bWJsZWQgdXAgYW5kIHdpbGwgbm90IHJ1bi4gWW91ciBjaGFsbGVuZ2UgaXMgdG8gcmUtb3JkZXIgaXQgc28gaXQgcnVucyBjb3JyZWN0bHkuIEl0IHNob3VsZCBwcmludCBvdXQgc3VtbWFyeSBzdGF0aXN0aWNzIGZvciBzZWFzb24gZ29hbCByYXRpbyBhbmQgYWdlIGJhbmQgZ29hbCByYXRpb3MsIGFzIHdlbGwgYXMgd2hpY2ggeWVhciB3YXMgaGlzIG1vc3QgYW5kIGxlYXN0IHByb2xpZmljLCBhbmQgaG93IG1hbnkgeWVhcnMgdGhhdCB0b29rIGhpbS4gCgpgYGB7ciBlcnJvcj1UUlVFfQojIHByaW50IGNhcmVlciByYXRpbwpjYXJlZXJHb2FsUmF0aW8KCiMgd2hpY2ggc2Vhc29uIGhhZCB0aGUgd29yc3QgZ29hbCByYXRpbwpzZWFzb25bd2hpY2gubWF4KGdvYWxSYXRpbyldCgojIGNvbWJpbmUgYWdlIGJhbmQgcmF0aW9zIHRvIGEgdmVjdG9yCmFnZUdvYWxSYXRpbyA8LSBjKHJvdW5kKG1lYW4odGVlbmFnZUdvYWxSYXRpbyksIGRpZ2l0cyA9IDIpLCAKICAgICAgICAgICAgICByb3VuZChtZWFuKHR3ZW50aWVzR29hbFJhdGlvKSwgZGlnaXRzID0gMiksCiAgICAgICAgICAgICAgcm91bmQobWVhbih0aGlydGllc0dvYWxSYXRpbyksIGRpZ2l0cyA9IDIpKQoKIyBhZGQgaW4gYXBwZWFyYW5jZSwgZ29hbCBhbmQgc2Vhc29uIGRhdGEKYXBwZWFyYW5jZXMgPC0gYyg5LDI1LDM2LDQwLDUxLDUzLDU1LDYwLDUwLDQ2LDU3LDQ5LDUyLDU0LDUwLDQ0KQpnb2FscyA8LSBjKDEsOCwxNywxNiwzOCw0Nyw1Myw3Myw2MCw0MSw1OCw0MSw1NCw0NSw1MSwzMSkKc2Vhc29uIDwtIGMoMjAwNCwyMDA1LDIwMDYsMjAwNywyMDA4LDIwMDksMjAxMCwyMDExLDIwMTIsCiAgICAgICAgICAgIDIwMTMsMjAxNCwyMDE1LDIwMTYsMjAxNywyMDE4LDIwMTkpCgojIHdoaWNoIHNlYXNvbiBoYWQgdGhlIGJlc3QgZ29hbCByYXRpbwpzZWFzb25bd2hpY2gubWluKGdvYWxSYXRpbyldCgojIGdvYWwgcmF0aW8gcGVyIGFnZSBiYW5kICh0ZWVuYWdlciwgMjAncywgMzAncykKdGVlbmFnZUdvYWxSYXRpbyA8LSBnb2FsUmF0aW9bMTozXQp0d2VudGllc0dvYWxSYXRpbyA8LSBnb2FsUmF0aW9bNDoxM10KdGhpcnRpZXNHb2FsUmF0aW8gPC0gZ29hbFJhdGlvWzE0OjE2XQoKIyBzdW1tYXJ5IHJlc3VsdHMKc3VtbWFyeShnb2FsUmF0aW8pCnN1bW1hcnkoYWdlR29hbFJhdGlvKQoKIyBob3cgbWFueSB5ZWFycyBwbGF5aW5nIHRvIHJlYWNoIGJlc3QgZ29hbCByYXRpbwpzZWFzb25bd2hpY2gubWluKGdvYWxSYXRpbyldIC0gc2Vhc29uWzFdCgojIHdvcmsgb3V0IGFwcGVhcmFuY2UgdG8gZ29hbCByYXRpbyBwZXIgc2Vhc29uIGFuZCB0b3RhbCBjYXJlZXIgcmF0aW8KZ29hbFJhdGlvIDwtIHJvdW5kKGFwcGVhcmFuY2VzL2dvYWxzLCBkaWdpdHMgPSAyKQpjYXJlZXJHb2FsUmF0aW8gPC0gcm91bmQoc3VtKGFwcGVhcmFuY2VzKS9zdW0oZ29hbHMpLCBkaWdpdHMgPSAyKQpgYGAKCg==